package net.jueb.juebCore.net.codec;

import java.nio.ByteOrder;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import net.jueb.juebCore.net.message.AppMessage;
import net.jueb.juebCore.net.message.AppBuffer;
import net.jueb.util4j.bytesStream.bytes.HexUtil;

/**
 *内部服务器消息解码器
 * 总长度=长度头(4)+校验位(4)+消息码(4)+数据body
 * 长度头值=4+4+dataLen
 * 校验位=校验位后面的所有字节计算值(type+code+data)
 */
public class AppMsgDecoder extends ByteToMessageDecoder {
	public final static int DEFALUT_PACK_SIZE = 64 * 1024 * 1024;
	protected final Logger _log = LoggerFactory.getLogger(getClass());
	private int maxPackSize = 64 * 1024 * 1024;
	protected final boolean validMsg;
	public static int CHECK_VALUE=0xFF;

	public AppMsgDecoder(boolean validMsg) {
		this.validMsg=validMsg;
	}

	public AppMsgDecoder(int size,boolean validMsg) {
		this.validMsg=validMsg;
	}

	@SuppressWarnings("deprecation")
	@Override
	public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
			throws Exception {
		int readableBytes = in.readableBytes();
		if (readableBytes < 12) {//12=总长度头(4)+校验位(4)+消息码(4)
			return;
		}
		ByteBuf din = in.order(ByteOrder.LITTLE_ENDIAN);// 高低位
		din.markReaderIndex();
		int lengthHead = din.readInt();//长度头4字节
		int vaild = din.readInt();//效验位4字节
		int code=din.readInt();//消息码4字节
		int dataLen=lengthHead-4-4;//去掉校验位大小消息头的数据长度
		//检查包长度
		if(maxPackSize > 0 && lengthHead>maxPackSize)
		{
			din.resetReaderIndex();
			_log.error(ctx.channel().toString()+":消息长度超出范围lengthHead="+lengthHead+",vaild="+vaild+",code="+code+",dataLen="+dataLen);
			ctx.close();
			return;
		}
		//检查数据长度
		if(dataLen<0)
		{
			din.resetReaderIndex();
			_log.error(ctx.channel().toString()+":消息数据长度错误lengthHead="+lengthHead+",vaild="+vaild+",code="+code+",dataLen="+dataLen);
			ctx.close();
			return;
		}
		//检查数据是否完整
		if(dataLen>0 && din.readableBytes()<dataLen)
		{//如果剩余数据还未到达则等待下一次读事件(排除心跳)
			din.resetReaderIndex();
			return;
		}
		byte[] contentData=new byte[dataLen];//消息数据
		din.readBytes(contentData, 0, contentData.length);
		if(validMsg)
		{
			//校验数据
			AppBuffer validData=new AppBuffer();//需要校验的数据(包含消息码+数据)
			validData.writeInt(code);//消息码
			validData.writeBytes(contentData);//消息数据
			byte[] validDataArray=validData.getBytes();//待校验的数据,包含
			//校验要带小消息头头校验
			int currentValid=calculateCheckSum(validDataArray);
			if (vaild != currentValid) 
			{
				din.resetReaderIndex();
				_log.error(ctx.channel()+":校验错误,validDataArray:\n"+HexUtil.SimplePrettyHexDump(validDataArray, 0, validDataArray.length));
				ctx.close();
				return;
			}
		}
		AppBuffer contentBuffer=new AppBuffer();
		contentBuffer.writeBytes(contentData);
		AppMessage message = new AppMessage(code,contentBuffer);
		out.add(message);
//		_log.debug("decoded AppMessage:"+message+",ctx:"+ctx.pipeline().names());
	}

	private int calculateCheckSum(byte[] b) {
		int val1 = CHECK_VALUE;
		int i = 0; // 从数据byte[] 第0位开始
		int len = b.length;
		while (i < len) {

			val1 += b[i++] & 0xff; // byte[] 数据流
		}
		return (val1) & 0x8F8F;
	}
}
